﻿class Point3
{
public:
	Point3();
	~Point3();
	Point3(double, double, double);
	Point3(const Point3& p);
	friend Point3 operator +(const Point3& p0, const Point3& p1);//дЫЫуЗ?жиди
	friend Point3 operator -(const Point3& p0, const Point3& p1);
	friend Point3 operator *(const Point3& p, double scalar);
	friend Point3 operator *(double scalar, const Point3& p);
	friend Point3 operator /(const Point3& p, double scalar);
public:
	double x, y, z;
};
#include "Point3.h"
Point3::Point3()
{
	x = y = z = 0;
}
Point3::~Point3()
{}
Point3::Point3(double xx, double yy, double zz)
{
	x = xx; y = yy; z = zz;
}
Point3::Point3(const Point3& p)
{
	x = p.x; y = p.y; z = p.z;
}
Point3 operator +(const Point3& p0, const Point3& p1)
{
	return(Point3(p0.x + p1.x, p0.y + p1.y, p0.z + p1.z));
}
Point3 operator -(const Point3& p0, const Point3& p1)
{
	return(Point3(p0.x - p1.x, p0.y - p1.y, p0.z - p1.z));
}
Point3 operator *(const Point3& p, double scalar)
{
	return(Point3(p.x * scalar, p.y * scalar, p.z * scalar));
}
Point3 operator *(double scalar, const Point3& p)
{
	return(Point3(p.x * scalar, p.y * scalar, p.z * scalar));
}
Point3 operator /(const Point3& p, double scalar)
{
	return(Point3(p.x / scalar, p.y / scalar, p.z / scalar));
}
#include "Point3.h"

class BicubicBezierPatch
{
public:
	BicubicBezierPatch();
	~BicubicBezierPatch();
	void ReadControlPoint(Point3 P[4][4]);//读入16个控制点
	void DrawCurvedPatch();//绘制双三次Bezier曲面片
	void DrawControlGrid();//绘制控制网格
	void DrawControlPoint(); //绘制控制点
private:
	void LeftMultiplyMatrix(double M[][4], Point3 CP[][4]);//左乘顶点矩阵
	void RightMultiplyMatrix(Point3 P[][4], double M[][4]);//右乘顶点矩阵
	void TransposeMatrix(double M[][4]);//转置矩阵

public:
	Point3 P[4][4];//三维控制点
};
#include "GL/glut.h"
#include "BicubicBezierPatch.h"
#include <cmath>

#pragma once

BicubicBezierPatch::BicubicBezierPatch()
{
}


BicubicBezierPatch::~BicubicBezierPatch()
{
}

void BicubicBezierPatch::ReadControlPoint(Point3 CP[4][4])
{
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			this->P[i][j] = CP[i][j];
}

void BicubicBezierPatch::DrawCurvedPatch()
{
	double M[4][4];//系数矩阵Mbe
	M[0][0] = -1; M[0][1] = 3; M[0][2] = -3; M[0][3] = 1;
	M[1][0] = 3; M[1][1] = -6; M[1][2] = 3; M[1][3] = 0;
	M[2][0] = -3; M[2][1] = 3; M[2][2] = 0; M[2][3] = 0;
	M[3][0] = 1; M[3][1] = 0; M[3][2] = 0; M[3][3] = 0;
	Point3 P3[4][4];//曲线计算用控制点数组
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			P3[i][j] = P[i][j];
	LeftMultiplyMatrix(M, P3);//数字矩阵左乘三维点矩阵
	TransposeMatrix(M);//计算转置矩阵
	RightMultiplyMatrix(P3, M);//数字矩阵右乘三维点矩阵
	double Step = 0.1;//步长
	double u0, u1, u2, u3, v0, v1, v2, v3;//u，v参数的幂
	glColor3f(1, 1, 0);
	glLineWidth(1);
	glPushMatrix();
	for (double u = 0; u <= 1; u += Step)
	{
		glBegin(GL_LINE_STRIP);
		for (double v = 0; v <= 1; v += Step)
		{
			u3 = u * u * u, u2 = u * u, u1 = u, u0 = 1;
			v3 = v * v * v, v2 = v * v, v1 = v, v0 = 1;
			Point3 pt = (u3 * P3[0][0] + u2 * P3[1][0] + u1 * P3[2][0] + u0 * P3[3][0]) * v3
				+ (u3 * P3[0][1] + u2 * P3[1][1] + u1 * P3[2][1] + u0 * P3[3][1]) * v2
				+ (u3 * P3[0][2] + u2 * P3[1][2] + u1 * P3[2][2] + u0 * P3[3][2]) * v1
				+ (u3 * P3[0][3] + u2 * P3[1][3] + u1 * P3[2][3] + u0 * P3[3][3]) * v0;

			glVertex3d(pt.x, pt.y, pt.z);
		}
		glEnd();
	}

	for (double v = 0; v <= 1; v += Step)
	{
		glBegin(GL_LINE_STRIP);
		for (double u = 0; u <= 1; u += Step)
		{
			u3 = u * u * u; u2 = u * u; u1 = u; u0 = 1; v3 = v * v * v; v2 = v * v; v1 = v; v0 = 1;
			Point3 pt = (u3 * P3[0][0] + u2 * P3[1][0] + u1 * P3[2][0] + u0 * P3[3][0]) * v3
				+ (u3 * P3[0][1] + u2 * P3[1][1] + u1 * P3[2][1] + u0 * P3[3][1]) * v2
				+ (u3 * P3[0][2] + u2 * P3[1][2] + u1 * P3[2][2] + u0 * P3[3][2]) * v1
				+ (u3 * P3[0][3] + u2 * P3[1][3] + u1 * P3[2][3] + u0 * P3[3][3]) * v0;
			glVertex3d(pt.x, pt.y, pt.z);
		}
		glEnd();
	}
	glPopMatrix();
}


void BicubicBezierPatch::LeftMultiplyMatrix(double M[][4], Point3 P[][4])//左乘矩阵M*P
{
	Point3 T[4][4];//临时矩阵
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			T[i][j] = M[i][0] * P[0][j] + M[i][1] * P[1][j] + M[i][2] * P[2][j] + M[i][3] * P[3][j];
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			P[i][j] = T[i][j];
}

void BicubicBezierPatch::RightMultiplyMatrix(Point3 P[][4], double M[][4])//右乘矩阵P*M
{
	Point3 T[4][4];//临时矩阵
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			T[i][j] = P[i][0] * M[0][j] + P[i][1] * M[1][j] + P[i][2] * M[2][j] + P[i][3] * M[3][j];
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			P[i][j] = T[i][j];
}

void BicubicBezierPatch::TransposeMatrix(double M[][4])//转置矩阵
{
	double T[4][4];//临时矩阵
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			T[j][i] = M[i][j];
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			M[i][j] = T[i][j];
}

void BicubicBezierPatch::DrawControlGrid()//绘制控制网格
{
	Point3 P2[4][4];//二维控制点
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
		{
			P2[i][j].x = P[i][j].x;
			P2[i][j].y = P[i][j].y;
			P2[i][j].z = P[i][j].z;
		}
	glColor3f(0, 1, 0);
	glLineWidth(3);

	for (int i = 0; i < 4; i++)
	{
		glBegin(GL_LINE_STRIP);
		for (int j = 0; j < 4; j++)
			glVertex3d(P2[i][j].x, P2[i][j].y, P2[i][j].z);
		glEnd();
	}


	for (int j = 0; j < 4; j++)
	{
		glBegin(GL_LINE_STRIP);
		for (int i = 0; i < 4; i++)
			glVertex3d(P2[i][j].x, P2[i][j].y, P2[i][j].z);
		glEnd();
	}

}
void BicubicBezierPatch::DrawControlPoint()//绘制控制
{
	glColor3f(1, 0, 0);
	glPointSize(5);
	glBegin(GL_POINTS);
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			glVertex3d(P[i][j].x, P[i][j].y, P[i][j].z);
	glEnd();
}
//键w、a、z、s控制曲面旋转；
#include <GL/glut.h>
#include <iostream>
#include <cstdlib>
#include "BicubicBezierPatch.h"

static GLint width = 800, height = 800;
GLfloat oldx, oldy;
double alpha_x = 0.0;
double alpha_y = 0.0;

static int n = 0;

Point3 P0[4][4];
Point3 P1[4][4];
Point3 P2[4][4];
BicubicBezierPatch patch0;
BicubicBezierPatch patch1;
BicubicBezierPatch patch2;

void init_controlpoint();
void init()
{
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-10.0, 10.0, -10.0, 10.0, -10.0, 10);
	glMatrixMode(GL_MODELVIEW);
	// Set the clear color to black
	glClearColor(0.0, 0.0, 0.0, 0.0); //black
	//init_controlpoint();
}

void  display()
{
	glClear(GL_COLOR_BUFFER_BIT);
	init_controlpoint();
	patch0.ReadControlPoint(P0);
	patch1.ReadControlPoint(P1);
	patch2.ReadControlPoint(P2);
	glRotatef(alpha_x, 1, 0, 0);
	glRotatef(alpha_y, 0, 1, 0);

	patch0.DrawCurvedPatch();
	patch1.DrawCurvedPatch();
	patch2.DrawCurvedPatch();
	glFlush();
}

void init_controlpoint()
{
	P0[0][0].x = 1.0; P0[0][0].y = 0.5; P0[0][0].z = -0;
	P0[0][1].x = 5.5; P0[0][1].y = 0.3; P0[0][1].z = -4;
	P0[0][2].x = 5.9; P0[0][2].y = -0.5; P0[0][2].z = -5;
	P0[0][3].x = 0.8; P0[0][3].y = -0.8; P0[0][3].z = -5;
	P0[1][0].x = 1.1; P0[1][0].y = 1.7; P0[1][0].z = -0;
	P0[1][1].x = 5.3; P0[1][1].y = 1.5; P0[1][1].z = -3;
	P0[1][2].x = 5.8; P0[1][2].y = 0.8; P0[1][2].z = -3;
	P0[1][3].x = 0.7; P0[1][3].y = 0.5; P0[1][3].z = -4;
	P0[2][0].x = 1.2; P0[2][0].y = -0.8; P0[2][0].z = -0;
	P0[2][1].x = 5.8; P0[2][1].y = -0.8; P0[2][1].z = -3;
	P0[2][2].x = 5.3; P0[2][2].y = -1.1; P0[2][2].z = -4;
	P0[2][3].x = 0.8; P0[2][3].y = -1.4; P0[2][3].z = -4;
	P0[3][0].x = 1.1; P0[3][0].y = -2.3; P0[3][0].z = -0;
	P0[3][1].x = 4.3; P0[3][1].y = -2.7; P0[3][1].z = -5;
	P0[3][2].x = 4.2; P0[3][2].y = -3.4; P0[3][2].z = -5;
	P0[3][3].x = 0.9; P0[3][3].y = -3.6; P0[3][3].z = -3;

	P1[0][0].x = 1.0; P1[0][0].y = 0.5; P1[0][0].z = -0;
	P1[0][1].x = -3.5; P1[0][1].y = 0.3; P1[0][1].z = -4;
	P1[0][2].x = -3.9; P1[0][2].y = -0.5; P1[0][2].z = -5;
	P1[0][3].x = 0.8; P1[0][3].y = -0.8; P1[0][3].z = -5;
	P1[1][0].x = 1.1; P1[1][0].y = 1.7; P1[1][0].z = -0;
	P1[1][1].x = -3.1; P1[1][1].y = 1.5; P1[1][1].z = -3;
	P1[1][2].x = -4.4; P1[1][2].y = 0.8; P1[1][2].z = -3;
	P1[1][3].x = 0.7; P1[1][3].y = 0.5; P1[1][3].z = -4;
	P1[2][0].x = 1.2; P1[2][0].y = -0.8; P1[2][0].z = -0;
	P1[2][1].x = -3.4; P1[2][1].y = -0.8; P1[2][1].z = -3;
	P1[2][2].x = -3.7; P1[2][2].y = -1.1; P1[2][2].z = -4;
	P1[2][3].x = 0.8; P1[2][3].y = -1.4; P1[2][3].z = -4;
	P1[3][0].x = 1.1; P1[3][0].y = -2.3; P1[3][0].z = -0;
	P1[3][1].x = -2.1; P1[3][1].y = -2.7; P1[3][1].z = -5;
	P1[3][2].x = -2.4; P1[3][2].y = -3.4; P1[3][2].z = -5;
	P1[3][3].x = 0.9; P1[3][3].y = -3.6; P1[3][3].z = -3;


}

void keyboard(unsigned char key, int x, int y)
{
	switch (key)
	{
	case 'd':
	case 'D':
		glutPostRedisplay();
		break;
	case 'w':
	case 'W':
		alpha_x += 360 * 1.0f / width;
		glutPostRedisplay();
		break;
	case 'z':
	case 'Z':
		alpha_x -= 360 * 1.0f / width;
		glutPostRedisplay();
		break;
	case 's':
	case 'S':
		alpha_y += 360 * 1.0f / height;
		glutPostRedisplay();
		break;
	case 'a':
	case 'A':
		alpha_y -= 360 * 1.0f / height;
		glutPostRedisplay();
		break;
	case 'x':
	case 'X':
		break;
	}
}

int  main(int  argc, char** argv)
{
	glutInit(&argc, argv);    // Initialize GLUT function callings
	//sets the initial display mode
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	// Set window position, from the left and top corner of the screen, in numbers of pixels 
	glutInitWindowPosition(200, 100);

	// Set window size (width, height) in number of pixels     
	glutInitWindowSize(800, 800);

	// Specify a window creation event 
	glutCreateWindow("Bezier Surface");
	init();	    // Invoke this function for initialization	
	//A window is reshaped

	// Specify the drawing function that is called when the window 
	glutDisplayFunc(display);         // is created or re-drew


	glutKeyboardFunc(keyboard);

	glutMainLoop();    // Enter the event processing loop

	return 0;          // Indicate normal termination 		
}
